use axum::response::IntoResponse;
use axum::routing::{get, post};
use axum::Router;
use mimalloc::MiMalloc;
use sq_global::APP_PORT_CFG;
use sq_schedule::spawn_cron_task;
use sq_strategy::biz::{
    avg_by_province, cons5d_diff_cons10d, cons7d_1pct_streak, extreme_pct_chg,
    longest_rising_streak,
};
use std::net::{Ipv4Addr, SocketAddr};
use tokio::net::TcpListener;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

#[tokio::main]
async fn main() {
    sq_config::init();
    sq_wecom::init().await;
    sq_tushare::init();
    sq_gpt::init();
    let _guard = sq_log::init();

    let port = sq_config::get_unchecked::<u16>(APP_PORT_CFG);
    let addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port);
    let listener = TcpListener::bind(&addr)
        .await
        .unwrap_or_else(|e| panic!("cannot bind addr err {}", e));

    spawn_cron_task!(
        "extreme_pct_chg",
        "0 0 17 * * Mon-Fri",
        extreme_pct_chg::run()
    );

    spawn_cron_task!(
        "cons7d_1pct_streak",
        "0 5 17 * * Mon-Fri",
        cons7d_1pct_streak::run()
    );

    spawn_cron_task!(
        "longest_rising_streak",
        "0 10 17 * * Mon-Fri",
        longest_rising_streak::run()
    );

    spawn_cron_task!(
        "avg_by_province",
        "0 15 17 * * Mon-Fri",
        avg_by_province::run()
    );
    spawn_cron_task!(
        "cons5d_diff_cons10d",
        "0 20 17 * * Mon-Fri",
        cons5d_diff_cons10d::run()
    );

    println!("Listening on {}", port);

    let router = Router::new()
        .route("/tushare/token", get(sq_restapi::tushare::chg_token))
        .route("/wechat/hook", get(sq_restapi::wecom::callback))
        .route("/wechat/recv_plain", get(sq_restapi::wecom::recv_plain))
        .route("/wechat/recv", post(sq_restapi::wecom::recv))
        .route("/strategy/{name}", get(sq_restapi::strategy::run_strategy))
        .fallback(handle_404);
    axum::serve(listener, router)
        .await
        .unwrap_or_else(|e| panic!("axum server start err {}", e));
}

pub async fn handle_404() -> impl IntoResponse {
    "api not found"
}
